package com.fwj.common.handle;

import com.alibaba.fastjson.JSONObject;
import com.fwj.common.entity.ChatMessage;
import com.fwj.core.common.common.CommonUtils;
import com.fwj.user.entity.user.UserBaseInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.websocket.*;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: fwj
 * @Data: 2022/5/3 14:06
 * @Version 1.0
 * @Description:
 */

@Component
public class ChatWebSocketHandle implements WebSocketHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(ChatWebSocketHandle.class);

    //最大消息堆积数
    private static final Integer MAX_LENGTH = 100;

    //定时刷新队列到数据库最长等待时间
    private static final Integer SCHEDULED_TASK_TIME = 60;

    //全局对象存储socket链接客户端,以用户编号为key，存储webSocket对象
    private volatile static ConcurrentHashMap<Long, ChatWebSocketHandle> chatWebSockets = null;

    //当前客户端总数
    private static AtomicInteger CURRENT_CLIENT_TOTAL = new AtomicInteger(0);

    //全局消息，使用队列.每个客户端各持有一个队列，因此是线程安全的
    private Queue queue = null;

    //用户编号
    private UserBaseInfo userBaseInfo;

    //私有会话信息
    private Session session;

    /**
     * 初始化webSocket
     **/
    private synchronized void initChatWebSocket(){
        //避免重复创建
        if (null == chatWebSockets){
            chatWebSockets = new ConcurrentHashMap<>();
        }
    }

    /**
     * 获取全局WebSocket（双检锁阻塞）
     * */
    private ConcurrentHashMap<Long, ChatWebSocketHandle> getChatWebSocket(){
        //双检锁获取对象
        if (null == chatWebSockets){
            initChatWebSocket();
        }
        return chatWebSockets;
    }

    /**
     * 初始化个人信息
     * */
    private void initPrivateInfo(UserBaseInfo userBaseInfo, Session session) {
        this.userBaseInfo = userBaseInfo;
        this.session = session;
        this.queue = new LinkedList();
    }

    private ChatMessage buildChatMessage(String message) {
        ChatMessage chatMessage = JSONObject.parseObject(message,ChatMessage.class);
        chatMessage.setMessageId(CommonUtils.generateUniqueNumber());
        chatMessage.setCreateTime(LocalDateTime.now());
        return chatMessage;
    }

    /**
     * 私聊消息
     * */
    public void sendMessage(String message, Long userNumber) throws IOException {
        if (chatWebSockets.containsKey(userNumber)){
            ChatWebSocketHandle webSocket = chatWebSockets.get(userNumber);
            if (null != webSocket){
                webSocket.session.getBasicRemote().sendText(message);
            }
        }
        session.getBasicRemote().sendText("emo");
    }

    /**
     * 群消息(在一个群的都接受到消息)
     * */
    public void sendMessageGroup(String message, Long groupNumber){

    }


    /**
     * 广播消息（所有用户都接收消息）
     * */
    public void broadcast(String message){
        for (ChatWebSocketHandle item : chatWebSockets.values()) {
            //异步广播消息给所有人
            item.session.getAsyncRemote().sendText(message);
            LOGGER.info("用户{}群发消息: {}",userBaseInfo.getNumber(),message);
        }
    }

    /**
     * Spring封装 创建webSocket链接
     * @param webSocketSession
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
//双检锁施加对象
        if (null == chatWebSockets){
            initChatWebSocket();
        }
        // 校验用户身份
        UserBaseInfo userBaseInfo = (UserBaseInfo) webSocketSession.getAttributes().get("userInfo");
        //初始化个人信息
        initPrivateInfo(userBaseInfo,session);
        //添加webSocket到全局Map
        chatWebSockets.put(userBaseInfo.getNumber(), this);
        LOGGER.info("Chat创建新的WebSocket链接,链接用户为： {} \n"
                + "当前链接总数： {}" , this.userBaseInfo.getNumber(), CURRENT_CLIENT_TOTAL.incrementAndGet());
    }

    /**
     * @param webSocketSession
     * @param webSocketMessage
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        ChatMessage chatMessage = buildChatMessage((String) webSocketMessage.getPayload());
        switch (chatMessage.getType()){
            case "private":
                sendMessage(chatMessage.getContent(), chatMessage.getTo());
                break;
            case "group":
                sendMessageGroup(chatMessage.getContent(),5L);
                break;
            case "broadcast":
                broadcast(chatMessage.getContent());
                break;
            default:
                break;
        }
        LOGGER.info("接收来自客户端{}的消息: {}",this.userBaseInfo.getNumber(),webSocketMessage.getPayload());
    }

    /**
     * @param webSocketSession
     * @param throwable
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        LOGGER.error("Error!!! => {}",throwable.getMessage());
    }

    /**
     * @param webSocketSession
     * @param closeStatus
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        if (null == chatWebSockets){
            LOGGER.error("不存在ChatWebSocket链接");
            return;
        }
        chatWebSockets.remove(this);
        LOGGER.info("Chat销毁WebSocket链接,退出用户为： {}\n" +
                "当前链接总数： {}" , this.userBaseInfo.getNumber(), CURRENT_CLIENT_TOTAL.decrementAndGet());
    }

    /**
     * @return
     */
    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}
